﻿Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL
Class ShaderBase
    Protected program As Integer

    Public ReadOnly Property programID As Integer
        Get
            Return program
        End Get
    End Property

    Public Sub Use()
        GL.UseProgram(program)
    End Sub

End Class

Class ShaderManager
    Public Shared kv As New Dictionary(Of String, ShaderBase)
    Private Sub New()
    End Sub

    Public Shared Sub Add(name As String, shaderprogram As ShaderBase)
        kv.Add(name, shaderprogram)
    End Sub

    Public Shared Sub Remove(name As String)
        kv.Remove(name)
    End Sub

    Public Shared Function Find(name As String) As Integer
        Return kv(name).programID
    End Function

    Private Shared curProgram As Integer
    Public Shared ReadOnly Property CurrentProgram As Integer
        Get
            Return curProgram
        End Get
    End Property

    Public Shared Function Active(name As String) As Integer
        Dim r = kv(name)
        r.Use()
        curProgram = r.programID
        Return r.programID
    End Function

    Public Shared Function FromVS(vs As String) As ShaderBase
        Return ShaderProgramVS.Load(vs)
    End Function

    Public Shared Function FromVSFS(vs As String, fs As String) As ShaderBase
        Return ShaderProgramVSFS.Load(vs, fs)
    End Function

    Public Shared Function FromVSGSFS(vs As String, gs As String, fs As String) As ShaderBase
        Return ShaderProgramVSGSFS.Load(vs, gs, fs)
    End Function
End Class

Class ShaderProgramVS
    Inherits ShaderBase
    Protected Shared self As ShaderProgramVS
    Protected vshader As Integer
    Protected Sub New(vs As String)
        program = GL.CreateProgram()
        vshader = GL.CreateShader(ShaderType.VertexShader)

        GL.ShaderSource(vshader, vs)
        GL.CompileShader(vshader)
        Dim vsLog As String = GL.GetShaderInfoLog(vshader)
        If vsLog.Contains("error") Then Throw New Exception(vsLog)
        GL.AttachShader(program, vshader)
        GL.LinkProgram(program)
        Dim programLog As String = GL.GetProgramInfoLog(program)
        If programLog.Contains("error") Then Throw New Exception(programLog)
    End Sub

    Public Shared Function Load(vs As String)
        Return New ShaderProgramVS(vs)
    End Function
End Class

Class ShaderProgramVSGSFS
    Inherits ShaderBase
    Protected vshader As Integer
    Protected gshader As Integer
    Protected fshader As Integer

    Protected Sub New(vs As String, gs As String, fs As String)
        program = GL.CreateProgram()
        vshader = GL.CreateShader(ShaderType.VertexShader)
        If gs IsNot Nothing Then
            gshader = GL.CreateShader(ShaderType.GeometryShader)
        End If
        fshader = GL.CreateShader(ShaderType.FragmentShader)

        GL.ShaderSource(vshader, vs)
        GL.CompileShader(vshader)
        Dim vsLog As String = GL.GetShaderInfoLog(vshader)
        If vsLog.Contains("error") Then Throw New Exception(vsLog)

        If gs IsNot Nothing Then
            GL.ShaderSource(gshader, gs)
            GL.CompileShader(gshader)
            Dim gsLog As String = GL.GetShaderInfoLog(gshader)
            If gsLog.Contains("error") Then Throw New Exception(gsLog)
        End If

        GL.ShaderSource(fshader, fs)
        GL.CompileShader(fshader)
        Dim fsLog As String = GL.GetShaderInfoLog(fshader)
        If fsLog.Contains("error") Then Throw New Exception(fsLog)

        GL.AttachShader(program, vshader)
        If gs IsNot Nothing Then
            GL.AttachShader(program, gshader)
        End If
        GL.AttachShader(program, fshader)
        GL.LinkProgram(program)
        Dim programLog As String = GL.GetProgramInfoLog(program)
        If programLog.Contains("error") Then Throw New Exception(programLog)
    End Sub

    Public Shared Function Load(vs As String, gs As String, fs As String)
        Return New ShaderProgramVSGSFS(vs, gs, fs)
    End Function

End Class

Class ShaderProgramVSFS
    Inherits ShaderBase
    Protected vshader As Integer
    Protected fshader As Integer

    Protected Sub New(vs As String, fs As String)
        program = GL.CreateProgram()
        vshader = GL.CreateShader(ShaderType.VertexShader)
        fshader = GL.CreateShader(ShaderType.FragmentShader)

        GL.ShaderSource(vshader, vs)
        GL.CompileShader(vshader)
        Dim vsLog As String = GL.GetShaderInfoLog(vshader)
        If vsLog.Contains("error") Then Throw New Exception(vsLog)

        GL.ShaderSource(fshader, fs)
        GL.CompileShader(fshader)
        Dim fsLog As String = GL.GetShaderInfoLog(fshader)
        If fsLog.Contains("error") Then Throw New Exception(fsLog)
        GL.AttachShader(program, vshader)
        GL.AttachShader(program, fshader)
        GL.LinkProgram(program)
        Dim programLog As String = GL.GetProgramInfoLog(program)
        If programLog.Contains("error") Then Throw New Exception(programLog)
    End Sub

    Public Shared Function Load(vs As String, fs As String)
        Return New ShaderProgramVSFS(vs, fs)
    End Function
End Class
